package com.vip.mongofile.service.component;

import com.vip.common.response.ErrorCode;
import com.vip.common.response.Result;
import com.vip.common.response.Results;
import com.vip.mongofile.constant.FileStorageEnum;
import com.vip.mongofile.dao.FileRepository;
import com.vip.mongofile.model.MongoFile;
import com.vip.mongofile.service.impl.AbstractFileStorageService;
import com.vip.mongofile.util.SpringBeanUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 文件存储客户端
 * @Date: 2020/12/07 09:56
 * @Author: wp
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class FileStorageClient implements InitializingBean, ApplicationContextAware {

    private final FileRepository fileRepository;
    private final Map<FileStorageEnum, AbstractFileStorageService> typeAndFileStorage = new EnumMap<>(FileStorageEnum.class);

    /**
     * Service 初始化
     */
    @Override
    public void afterPropertiesSet() {
        //完成所有文件存储策略加载
        Map<String, AbstractFileStorageService> fileStorageMap = SpringBeanUtils.getInstance().getBeansOfType(AbstractFileStorageService.class);
        fileStorageMap.forEach((key, value) -> typeAndFileStorage.put(value.getEnumType(), value));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringBeanUtils.getInstance().setCfgContext(applicationContext);
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    public Result<MongoFile> doUpload(MultipartFile file) {
        return dynamicDetermineService(file.getSize()).uploadFile(file);
    }

    /**
     * 删除文件
     *
     * @param mongoId
     * @return
     */
    public Result<String> doDelete(String mongoId) {
        Result<String> result = dynamicDetermineService(null).deleteFile(mongoId);
        if (!result.isSuccess()) {
            result = typeAndFileStorage.get(FileStorageEnum.MONGO_BIG).deleteFile(mongoId);
        }
        return result;
    }

    /**
     * 查询文件
     *
     * @param mongoId
     * @return
     */
    public Result<MongoFile> doGetFileById(String mongoId) {
        Result<MongoFile> result = dynamicDetermineService(null).getFileById(mongoId);
        if (!result.isSuccess()) {
            result = typeAndFileStorage.get(FileStorageEnum.MONGO_BIG).getFileById(mongoId);
        }
        return result;
    }

    /**
     * 动态选择ServiceBean
     *
     * @param size
     * @return
     */
    private AbstractFileStorageService dynamicDetermineService(Long size) {
        FileStorageEnum fileStorageEnum = FileStorageEnum.getFileStorageEnum(FileStorageEnum.MONGO.getType());
        if (size != null) {
            // 如果超出16M，则使用大文件上传服务
            long BIG_FILE_SIZE = 16 * 1024 * 1024;
            if (size > BIG_FILE_SIZE) {
                fileStorageEnum = FileStorageEnum.MONGO_BIG;
            }
        }
        return typeAndFileStorage.get(fileStorageEnum);
    }

    /**
     * 分页查询文件信息
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    public Result<List<MongoFile>> listFilesByPage(int pageNo, int pageSize) {
        try {
            Pageable pageable = PageRequest.of((pageNo - 1) * pageSize, pageSize);
            Page<MongoFile> page = fileRepository.findAll(pageable);
            return Results.newSuccessResult(page.getContent().stream().filter(content -> {
                content.setContent(null);
                return true;
            }).collect(Collectors.toList()), "查询成功");
        } catch (Exception e) {
            log.error("分页查询文件出错", e);
        }
        return Results.newFailResult(ErrorCode.FILE_ERROR, "查询失败");
    }
}
